#pragma once
/**
 * @file Channel.hpp
 * @author 1102403684@qq.com
 * @brief 对一个描述符进行监控事件管理
 * @version 0.1
 * @date 2024-10-03
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <cstdint>
#include <functional>
#include <sys/epoll.h>

#include "../common/logger.hpp"

using EventCallBack = std::function<void()>;

class EventLoop; // 前置声明EventLoop类
class Channel
{
public:
    Channel(EventLoop *eventloop, int fd) : fd_(fd), events_(0), revents_(0), eventloop_(eventloop) {}
    int get_fd() { return fd_; }
    bool is_read_monitor() { return events_ & EPOLLIN; }
    bool is_write_monitor() { return events_ & EPOLLOUT; }

    /*TODO 这几项操作不仅要在events_里修改，还需要应用到底层的epoll中*/
    void enable_read_event()
    {
        (events_ |= EPOLLIN);
        update_epoll();
    }
    void enable_write_event()
    {
        (events_ |= EPOLLOUT);
        update_epoll();
    }
    void disable_read_event()
    {
        (events_ &= ~EPOLLIN);
        update_epoll();
    }
    void disable_write_event()
    {
        (events_ &= ~EPOLLOUT);
        update_epoll();
    }
    void disable_all_event()
    {
        events_ = 0;
        revents_ = 0; //防止因为读触发且没有多余写数据写要 直接关闭连接后导致的出错
        remove_epoll();
    } // 解除所有监控

    void remove_epoll(); // 移除监控,要调用eventloop进行移除
    void update_epoll();

    void set_read_callback(const EventCallBack &callback) { read_callback_ = callback; }
    void set_write_callback(const EventCallBack &callback) { write_callback_ = callback; }
    void set_error_callback(const EventCallBack &callback) { error_callback_ = callback; }
    void set_close_callback(const EventCallBack &callback) { close_callback_ = callback; }
    void set_event_callback(const EventCallBack &callback) { event_callback_ = callback; }

    void set_revents(uint32_t events) { revents_ = events; } // 由外部(Eventloop)设置实际继续的事件
    uint32_t get_revnets() { return revents_; }
    uint32_t get_events() { return events_; }
    void handle_event(); // 触发事件，调用此函数

private:
    int fd_;
    uint32_t events_;  // 需要监控的事件
    uint32_t revents_; // 实际触发的事件
    EventCallBack read_callback_;
    EventCallBack write_callback_;
    EventCallBack error_callback_;
    EventCallBack close_callback_; // 连接断开回调
    EventCallBack event_callback_; // 任意事件回调
    EventLoop *eventloop_;
};

/*------------------------implement-------------------------*/

void Channel::handle_event()
{
    if (revents_ & EPOLLERR)
    {
        LOG_DEBUG("触发handle error revents {}, fd {}", revents_, fd_);
        if (error_callback_)
            error_callback_();
        return;
    }


    // TODO一次只执行一个事件，因为读也有可能释放连接 后面进行了更改读不会释放连接，，服了
    if ((revents_ & EPOLLIN) || (revents_ & EPOLLRDHUP) || (revents_ & EPOLLPRI))
    {
        if (read_callback_)
            read_callback_();
    }
    
    if (revents_ & EPOLLOUT) /** 可能会释放连接，一次只处理一个 */
    {
        if (write_callback_)
            write_callback_();
    }
    else if (revents_ & EPOLLHUP)
    {
        if (error_callback_)
            error_callback_();
    }

    if (event_callback_)
    {
        event_callback_(); // 放到处理完毕后调用，防止非活跃立即被剔出
    }
}
